﻿// Created by amoylel on 05/18/2017.
// Copyright (c) 2017 amoylel All rights reserved.

#ifndef AMO_ANY_HPP__
#define AMO_ANY_HPP__

#include <string>
#include <map>
#include <memory>
#include <vector>
#include <type_traits>
#include <amo/json.hpp>
#include <amo/nil.hpp>
#include <amo/stdint.hpp>
#include <amo/date_time.hpp>
#include <amo/blob.hpp>
#include <amo/bigstr.hpp>

/*!
 * @namespace	amo
 *
 * @brief	.
 */
namespace amo {




    /*!
     * @typedef	amo::nil Nil
     *
     * @brief	函数无返回值时，线程/进程之间同步时 返回Nil表示void.
     * 			对应JS中的null
     */
    typedef amo::nil Nil;
    
    /*!
     * @class	undefined
     *
     * @brief	调用C++时返回Undefined对应JS中的undefined.
     */
    class undefined {};
    
    /*!
     * @class	nonReturn
     *
     * @brief	JS调用C++不需要向JS返回结果，如异步回调函数.
     */
    class nonReturn {};
    
    /*!
     * @class	nothing
     *
     * @brief	JS调用C++不需要向JS返回结果，跟NonReturn差不多，分不清了.
     */
    class nothing {};
    
    /**
     * @class	Deadlock
     *
     * @brief	进程死锁时的返回类型.
     */
    
    class deadlock {};
    /*!
     * @class	Unknown
     *
     * @brief	未知结果，正常不会出现.
     */
    class Unknown {};
    
    // 前置声明
    class any;
    
    
    /*!
     * @fn	template<typename T> static std::string valueToString(const T& val)
     *
     * @brief	将类型转换成字符串.
     *
     * @tparam	T	类型.
     * @param	val	类型实例.
     *
     * @return	std::string.
     */
    template<typename T> static std::string valueToString(const T& val) {
        amo::u8json json;
        json.put(val);
        return json.to_string();
    }
    /*!
     * @fn	template<typename T> static std::string AnyToString(const T& val);
     *
     * @brief	将任意类型转换为String.
     * 			将函数不能被调用，只能使用特化版本
     *
     * @tparam	T	类型.
     * @param	val	类型实例.
     *
     * @return	std::string.
     */
    template<typename T> static std::string anyToString(const T& val);
    
    template<> static std::string anyToString(const bool& val) {
        return valueToString<bool>(val);
    }
    template<> static std::string anyToString(const char& val) {
        return valueToString<char>(val);
    }
    template<> static std::string anyToString(const int& val) {
        return valueToString<int>(val);
    }
    template<> static std::string anyToString(const int64_t& val) {
        return valueToString<int64_t>(val);
    }
    template<> static std::string anyToString(const uint64_t& val) {
        return valueToString<uint64_t>(val);
    }
    template<> static std::string anyToString(const double& val) {
        return valueToString<double>(val);
    }
    template<> static std::string anyToString(const std::string& val) {
        return val;
    }
    template<> static std::string anyToString<Nil>(const Nil& val) {
        return valueToString<std::string>("nil");
    }
    template<> static std::string anyToString<undefined>(const undefined& val) {
        return valueToString<std::string>("undefined");
    }
    template<> static std::string anyToString<nonReturn>(const nonReturn& val) {
        return valueToString<std::string>("nonreturn");
    }
    template<> static std::string anyToString<deadlock>(const deadlock& val) {
        return valueToString<std::string>("deadlock");
    }
    template<> static std::string anyToString<amo::blob>(const amo::blob& val) {
        return val.get_name();
    }
    template<> static std::string anyToString<amo::bigstr>(const amo::bigstr& val) {
        return val.get_name();
    }
    template<> static std::string anyToString<amo::json_value>
    (const amo::json_value& val) {
        return val.to_string();
    }
    template<> static std::string anyToString<amo::json>(const amo::json& val) {
        return val.to_string();
    }
    template<> static std::string anyToString<amo::u8json>(const amo::u8json& val) {
        return val.to_string();
    }
    template<> static std::string anyToString<nothing>(const nothing& val) {
        return std::string();
    }
    
    template<> static std::string anyToString<date_time>(const date_time& val) {
        return val.to_string();
    }
    /*!
     * @fn	template<typename T> static T stringToValue(const std::string& val)
     *
     * @brief	将字符串转换为所给类型.
     *
     * @tparam	T	类型.
     * @param	val	输入字符串.
     *
     * @return	目标类型值.
     */
    template<typename T> static T stringToValue(const std::string& val) {
        amo::u8json json(val);
        return json.get<T>();
    }
    /*!
     * @fn	template<typename T> static T stringToAny(const std::string& val);
     *
     * @brief	将字符串转换为任意类型.
     *
     * @tparam	T	目标类型.
     * @param	val	输入字符串.
     *
     * @return	目标类型值.
     */
    template<typename T> static T stringToAny(const std::string& val);
    template<> static bool stringToAny(const std::string& val) {
        return stringToValue<bool>(val);
    }
    template<> static char stringToAny(const std::string& val) {
        return stringToValue<char>(val);
    }
    template<> static int stringToAny(const std::string& val) {
        return stringToValue<int>(val);
    }
    template<> static int64_t stringToAny(const std::string& val) {
        return stringToValue<int64_t>(val);
    }
    template<> static uint64_t stringToAny(const std::string& val) {
        return stringToValue<uint64_t>(val);
    }
    template<> static double stringToAny(const std::string& val) {
        return stringToValue<double>(val);
    }
    template<> static std::string stringToAny(const std::string& val) {
        return val;
    }
    template<> static amo::u8json stringToAny(const std::string& val) {
        return amo::u8json(val);
    }
    template<> static amo::json stringToAny(const std::string& val) {
        return amo::json(val);
    }
    
    template<> static Nil stringToAny(const std::string& val) {
        return Nil();
    }
    template<> static undefined stringToAny(const std::string& val) {
        return undefined();
    }
    template<> static deadlock stringToAny(const std::string& val) {
        return deadlock();
    }
    template<> static amo::blob stringToAny(const std::string& val) {
        return amo::blob(val);
    }
    template<> static amo::bigstr stringToAny(const std::string& val) {
        return amo::bigstr(val);
    }
    template<> static nonReturn stringToAny(const std::string& val) {
        return nonReturn();
    }
    template<> static nothing stringToAny(const std::string& val) {
        return nothing();
    }
    template<> static date_time stringToAny(const std::string& val) {
        return date_time::from_string(val);
    }
    /*!
     * @struct	any_value_type
     *
     * @brief	any类型判断类.
     *
     * @tparam	T	Generic type parameter.
     */
    template<typename T> struct any_value_type {
        static const char value = -1;
    };
    
    template<> struct any_value_type <Unknown> {
        static const char value = -1;
    };
    
    ///
    template<> struct any_value_type <nothing> {
        static const char value = 0;
    };
    template<> struct any_value_type <bool> {
        static const char value = 1;
    };
    template<> struct any_value_type <char> {
        static const char value = 2;
    };
    template<> struct any_value_type <int> {
        static const char value = 3;
    };
    template<> struct any_value_type <int64_t> {
        static const char value = 4;
    };
    template<> struct any_value_type <double> {
        static const char value = 5;
    };
    template<> struct any_value_type <std::string> {
        static const char value = 6;
    };
    template<> struct any_value_type <const char*> {
        static const char value = 7;
    };
    
    template<> struct any_value_type <uint64_t> {
        static const char value = 8;
    };
    
    // 辅助类
    template<> struct any_value_type <Nil> {
        static const char value = 21;
    };
    template<> struct any_value_type <undefined> {
        static const char value = 22;
    };
    template<> struct any_value_type <nonReturn> {
        static const char value = 23;
    };
    template<> struct any_value_type <deadlock> {
        static const char value = 24;
    };
    template<> struct any_value_type < any > {
        static const char value = 30;
    };
    
    
    // 自定义类型
    template<> struct any_value_type <std::map<std::string, std::string> > {
        static const char value = 40;
    };
    template<> struct any_value_type <amo::u8json> {
        static const char value = 41;
    };
    template<> struct any_value_type <amo::json> {
        static const char value = 41;
    };
    
    template<> struct any_value_type<std::vector<any> > {
        static const char value = 42;
    };
    template<> struct any_value_type <amo::date_time> {
        static const char value = 43;
    };
    
    template<> struct any_value_type <amo::blob> {
        static const char value = 44;
    };
    template<> struct any_value_type <amo::bigstr> {
        static const char value = 45;
    };
    /*!
     * @class	AnyData
     *
     * @brief	any 数据.
     */
    class AnyData {
    public:
        /*! @brief	实际类型. */
        char type;
        /*! @brief	序列化后的字符串. */
        std::string value;
    };
    /*!
     * @class	any
     *
     * @brief	any类，用于进程间数据通信统一类型.
     */
    class any  {
    public:
        any() {
            m_pData.reset(new AnyData());
            m_pData->type = 0;
        }
        
        any(char type_)  {
            m_pData.reset(new AnyData());
            m_pData->type = type_;
        }
        
        any(const any& rhs) {
            m_pData.reset(new AnyData());
            m_pData->value = rhs.value();
            m_pData->type = rhs.type();
        }
        
        any(char type_, const std::string& val_)  {
            m_pData.reset(new AnyData());
            m_pData->type = type_;
            m_pData->value = val_;
        }
        
        /*!
         * @fn	template<typename T> any::any(const T& val_)
         *
         * @brief	使用任意类型初始化.
         *
         * @tparam	T	Generic type parameter.
         * @param	val_	The value.
         */
        template<typename T> any(const T& val_) {
            m_pData.reset(new AnyData());
            m_pData->type = any_value_type<T>::value;
            m_pData->value = anyToString<T>(val_);
        }
        
        /*!
         * @fn	any::any(const char* val_)
         *
         * @brief	使用字符串初始化.
         *
         * @param	val_	The value.
         */
        any(const char* val_) {
            m_pData.reset(new AnyData());
            m_pData->type = any_value_type<std::string>::value;
            m_pData->value = anyToString<std::string>(val_);
        }
        
        ~any() { }
        
        any& operator=(const any& rhs) {
            m_pData->type = rhs.type();
            m_pData->value = rhs.value();
            return *this;
        }
        
        bool isValid() const {
            return type() != any_value_type<nothing>::value;
        }
        
        // 类型转换
        template<typename R> operator R() const {
            return stringToAny<R>(m_pData->value);
        }
        template<typename R> R As() const {
            return stringToAny<R>(m_pData->value);
        }
        
        // 类型判断
        template<typename T> bool is() const {
            return (type() == any_value_type<T>::value);
        }
        
        // 类型
        
        char& type() {
            return m_pData->type;
        }
        
        const char& type() const {
            return m_pData->type;
        }
        
        void type(const char& t) {
            m_pData->type = t;
        }
        
        // 数据
        
        std::string& value() {
            return m_pData->value;
        }
        
        const std::string& value() const {
            return m_pData->value;
        }
        
        void value(const std::string& val) {
            m_pData->value = val;
        }
        static any fromJson(const amo::json_value& json) {
            char type = json.get<char>("type");
            std::string val = json.get<std::string>("value");
            return any(type, val);
        }
        /*static any fromJson(const amo::u8json& json) {
            char type = json.get<char>("type");
            std::string val = json.get<std::string>("value");
            return any(type, val);
        }*/
        
        amo::u8json toJson() const {
            amo::u8json json;
            json.put("type", m_pData->type);
            json.put("value", m_pData->value);
            return json;
        }
        
        any clone() {
            return any(type(), value());
        }
        
        /*! @brief	实际类型数据. */
        std::shared_ptr<AnyData> m_pData;
    };
    
    
    template<> static std::string anyToString<any>(const any& val) {
        return val.value();
    }
    
    template<> static std::vector<any> stringToAny(const std::string& val) {
        std::vector<any> vec;
        amo::u8json json(val);
        
        if (!json.is_array()) {
            return vec;
        }
        
        std::vector<amo::u8json> jsonArr = json.to_array();
        
        for (auto& p : jsonArr) {
            vec.push_back(any::fromJson(p));
        }
        
        return vec;
    }
    
    template<> static std::string anyToString(const std::vector<any>& val) {
        amo::u8json jsonArr;
        jsonArr.set_array();
        
        for (auto p : val) {
            jsonArr.push_back(p.toJson());
        }
        
        return jsonArr.to_string();
    }
    
    
    
    /*!
    * @class	ValidAny
    *
    * @brief	A valid any.
    */
    
    class ValidAny {};
    
    /*!
    * @class	InvalidAny
    *
    * @brief	An invalid any.
    */
    
    class InvalidAny {};
    
    template<typename T>
    class GetAnyType {
    public:
        typedef typename std::conditional<any_value_type<T>::value
        == any_value_type<Unknown>::value, InvalidAny, ValidAny>::type Type;
    };
}

#endif // AMO_ANY_HPP__

